package com.jasiri.project.lib.dev.data

import android.annotation.SuppressLint
import android.app.ActivityManager
import android.app.usage.StorageStatsManager
import android.content.Context
import android.os.Build
import android.os.Environment
import android.os.StatFs
import android.os.storage.StorageManager
import com.google.gson.Gson
import com.jasiri.project.lib.dev.util.formatSysSize
import com.jasiri.project.lib.dev.util.formatZipString
import com.jasiri.project.lib.dev.util.getCommonData1
import com.jasiri.project.lib.dev.util.getCommonData2
import org.json.JSONObject
import java.io.File
import java.util.UUID

/**
 * storage
 */
class JasiriSysDataT4(val context: Context) {

    fun getSubmitDataT4(): String? {
        return try {
            val data = hashMapOf<String, Any>().apply {
                put("imei", "")
                put("containSd", getSysT4Data9())
                put("ramCanUse", getSysT4Data5(context))
                put("ramTotal", getCommonData1(context))
                put("cashCanUse", getSysT4Data7())
                put("cashTotal", getCommonData2())
                put("extraSD", getSysT4Data10())
                put("internalTotal", getSysT4Data1(context))
                put("internalAvailable", getSysT4Data2(context))
                put("ramDidUsed", getSysT4Data6(context))
                put("cashDidUsed", getSysT4Data8())
                put("sdCardTotal", getSysT4Data11())
            }
            Gson().toJson(data).trim().formatZipString()

        } catch (e: Exception) {
            null
        }
    }

    private fun getSysT4Data1(context: Context): String {
        return try {
            val jsonObject = getSysT4Data3(context)
            jsonObject.getString("total")
        } catch (e: Exception) {
            //
            "0"
        }
    }

    private fun getSysT4Data2(context: Context): String {
        return try {
            val jsonObject = getSysT4Data3(context)
            jsonObject.getString("available")
        } catch (e: Exception) {
            //
            "0"
        }
    }

    @SuppressLint("DiscouragedPrivateApi", "UsableSpace")
    private fun getSysT4Data3(context: Context): JSONObject {
        val unit = 1024f
        val version = Build.VERSION.SDK_INT
        val storeObj = JSONObject()
        try {
            if (version < Build.VERSION_CODES.M) {
                val storageManager =
                    context.getSystemService(Context.STORAGE_SERVICE) as StorageManager
                val getVolumeList = StorageManager::class.java.getDeclaredMethod("getVolumeList")
                val volumeList = getVolumeList.invoke(storageManager) as Array<*>
                var totalSize = 0L
                var availableSize = 0L
                volumeList.first()?.javaClass?.getDeclaredMethod("getPathFile")?.apply {
                    for (volume in volumeList) {
                        val file = invoke(volume) as File?
                        file?.let {
                            totalSize += file.totalSpace
                            availableSize += file.usableSpace
                        }
                    }
                }
                val totalStore = formatSysSize(totalSize.toFloat(), unit)
                val availableStore = formatSysSize(availableSize.toFloat(), unit)
                storeObj.put("total", totalStore)
                storeObj.put("available", availableStore)
                storeObj.put("used", "0")
            } else {
                val storageManager =
                    context.getSystemService(Context.STORAGE_SERVICE) as StorageManager
                var total = 0L
                var used = 0L
                val getVolumes = StorageManager::class.java.getDeclaredMethod("getVolumes")
                val getVolumeInfo = getVolumes.invoke(storageManager) as List<*>
                for (objInfo in getVolumeInfo) {
                    objInfo?.let { obj ->
                        val getType = obj.javaClass.getField("type")
                        val type = getType.getInt(obj)
                        if (type == 1) {
                            var totalSize = 0L
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                                val getFsUuid =
                                    obj.javaClass.getDeclaredMethod("getFsUuid")
                                val fsUuid = getFsUuid.invoke(obj) as String?
                                totalSize =
                                    getSysT4Data4(
                                        context,
                                        fsUuid ?: StorageManager.UUID_DEFAULT.toString()
                                    )
                            }
                            val isMountedReadable = obj.javaClass.getDeclaredMethod("isMountedReadable")
                            val readable = isMountedReadable.invoke(obj) as Boolean
                            if (readable) {
                                val file = obj.javaClass.getDeclaredMethod("getPath")
                                val f = file.invoke(obj) as File?
                                f?.let {
                                    if (totalSize == 0L) {
                                        totalSize = f.totalSpace
                                    }
                                    used += totalSize - f.freeSpace
                                    total += totalSize
                                }
                            }
                        } else if (type == 0) {
                            val isMountedReadable =
                                obj.javaClass.getDeclaredMethod("isMountedReadable")
                            val readable = isMountedReadable.invoke(obj) as Boolean
                            if (readable) {
                                val file = obj.javaClass.getDeclaredMethod("getPath")
                                val f = file.invoke(obj) as File?
                                f?.let {
                                    used += f.totalSpace - f.freeSpace
                                    total += f.totalSpace
                                }
                            }
                        }
                    }
                }
                val totalStore = formatSysSize(total.toFloat(), unit)
                val usedStore = formatSysSize(used.toFloat(), unit)
                val availableStore = formatSysSize((total - used).toFloat(), unit)
                storeObj.put("total", totalStore)
                storeObj.put("available", availableStore)
                storeObj.put("used", usedStore)
            }
        } catch (e: Exception) {
            //
        }
        return storeObj
    }

    private fun getSysT4Data4(context: Context, fsUuid: String): Long {
        return try {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                var id = StorageManager.UUID_DEFAULT
                if (fsUuid.isNotBlank()) {
                    id = UUID.fromString(fsUuid)
                }
                val stats =
                    context.getSystemService(Context.STORAGE_STATS_SERVICE) as StorageStatsManager?
                stats?.getTotalBytes(id) ?: -1
            } else {
                -1
            }
        } catch (e: Exception) {
            //
            -1
        }
    }

    private fun getSysT4Data5(paramContext: Context): String {
        return try {
            val memoryInfo = ActivityManager.MemoryInfo()
            (paramContext.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager).getMemoryInfo(
                memoryInfo
            )
            formatSysSize(memoryInfo.availMem.toFloat(), 1024f)
        } catch (e: java.lang.Exception) {
            //
            "0"
        }
    }

    private fun getSysT4Data6(paramContext: Context): String {
        return try {
            val memoryInfo = ActivityManager.MemoryInfo()
            (paramContext.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager).getMemoryInfo(
                memoryInfo
            )
            val didUsed = memoryInfo.totalMem - memoryInfo.availMem
            formatSysSize(didUsed.toFloat(), 1024f)
        } catch (e: java.lang.Exception) {
            //
            "0"
        }
    }

    private fun getSysT4Data7(): String {
        return try {
            val file = Environment.getDataDirectory()
            val statFs = StatFs(file.path)
            formatSysSize(
                (statFs.availableBlocksLong * statFs.blockSizeLong).toFloat(),
                1024f
            )
        } catch (e: java.lang.Exception) {
            //
            "0"
        }
    }

    private fun getSysT4Data8(): String {
        return try {
            val file = Environment.getDataDirectory()
            val statFs = StatFs(file.path)
            val total = statFs.blockCountLong * statFs.blockSizeLong
            val avail = statFs.availableBlocksLong * statFs.blockSizeLong
            val didUsed = total - avail
            formatSysSize(didUsed.toFloat(), 1024f)
        } catch (e: java.lang.Exception) {
            //
            "0"
        }
    }

    private fun getSysT4Data9(): String {
        return if (Environment.getExternalStorageState() == "mounted") {
            "YES"
        } else "NO"
    }

    private fun getSysT4Data10(): String {
        return "NO"
    }

    private fun getSysT4Data11(): String {
        return try {
            if (Environment.getExternalStorageState().equals("mounted", ignoreCase = true)) {
                val file = Environment.getExternalStorageDirectory()
                val statFs = StatFs(file.path)
                val l = statFs.blockSizeLong
                return formatSysSize((statFs.blockCountLong * l).toFloat(), 1024f)
            }
            "0GB"
        } catch (e: java.lang.Exception) {
            //
            "0GB"
        }
    }
}